﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Linq;
using System.Text;
using System.IO;

namespace QW.Core.Encrypt
{
    /// <summary>
    /// AES加密解密工具
    /// </summary>
    public sealed class AESHelper
    {
        #region 加密
        /// <summary>
        /// AES-CBC-PKCS7 加密(返回16进制结果)
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static byte[] Encrypt(byte[] str, byte[] key, byte[] iv)
        {
            //RijndaelManaged rm = new RijndaelManaged();
            SymmetricAlgorithm rm = Rijndael.Create();
            rm.Key = key;
            //rm.KeySize = 128;   //放开后加密结果一直变化
            //rm.BlockSize = 128;
            rm.Mode = CipherMode.CBC;
            rm.Padding = PaddingMode.PKCS7;
            if (iv != null) { rm.IV = iv; }
            var ctm = rm.CreateEncryptor();
            return ctm.TransformFinalBlock(str, 0, str.Length);
            /*
            ICryptoTransform cTransform = rm.CreateEncryptor();
            Byte[] result = cTransform.TransformFinalBlock(str, 0, str.Length);
            return result;
            */
        }
        /// <summary>
        /// AES-CBC-PKCS7 加密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key">密钥，32位以内</param>
        /// <param name="iv">向量,16位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string Encrypt(string str, string key= ConstData.DEFAULT_KEY, string iv = ConstData.DEFAULT_IV, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }

            if (key.Length > 32)
            {
                key = key.Substring(32);
            }
            key = key.PadRight(32, '0');
            if (iv.Length > 16)
            {
                iv = key.Substring(16);
            }
            iv = iv.PadRight(16, '0');

            byte[] str_arr = encode.GetBytes(str);
            byte[] key_arr = encode.GetBytes(key);
            byte[] iv_arr = null;
            if (!string.IsNullOrWhiteSpace(iv))
            {
                iv_arr = encode.GetBytes(iv);
            }
            byte[] arr_result = Encrypt(str_arr, key_arr, iv_arr);
            StringBuilder sb = new StringBuilder(50);
            foreach (byte b in arr_result)
            {
                sb.AppendFormat("{0:X2}", b);
            }
            return sb.ToString();
        }
        /// <summary>
        /// AES-CBC-PKCS7 加密(返回Base64结果)
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key">密钥，32位以内</param>
        /// <param name="iv">向量,16位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string EncryptToBase64(string str, string key = ConstData.DEFAULT_KEY, string iv = ConstData.DEFAULT_IV, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }
            if (key.Length > 32)
            {
                key = key.Substring(32);
            }
            key = key.PadRight(32, '0');
            if (iv.Length > 16)
            {
                iv = key.Substring(16);
            }
            iv = iv.PadRight(16, '0');
            byte[] str_arr = encode.GetBytes(str);
            byte[] key_arr = encode.GetBytes(key);
            byte[] iv_arr = null;
            if (!string.IsNullOrWhiteSpace(iv))
            {
                iv_arr = encode.GetBytes(iv);
            }
            byte[] resultArray = Encrypt(str_arr, key_arr, iv_arr);
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }
        #endregion

        #region 解密
        /// <summary>
        /// AES-CBC-PKCS7 解密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static byte[] Decrypt(byte[] str, byte[] key, byte[] iv)
        {
            //RijndaelManaged rm = new RijndaelManaged();
            SymmetricAlgorithm rm = Rijndael.Create();
            rm.Key = key;
            //rm.KeySize = 128;   //放开后一直会填充错误
            //rm.BlockSize = 128;
            rm.Mode = CipherMode.CBC;
            rm.Padding = PaddingMode.PKCS7;
            if (iv != null) { rm.IV = iv; }
            MemoryStream mStream = new MemoryStream();
            var ctm = rm.CreateDecryptor();
            return ctm.TransformFinalBlock(str, 0, str.Length);
            /*
            ICryptoTransform cTransform = rm.CreateDecryptor();
            Byte[] result = cTransform.TransformFinalBlock(str, 0, str.Length);
            return result;
            */
        }
        /// <summary>
        /// AES-CBC-PKCS7 解密
        /// </summary>
        /// <param name="str">Base64字符</param>
        /// <param name="key">密钥，32位以内</param>
        /// <param name="iv">向量,16位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string DecryptFromBase64(string str, string key = ConstData.DEFAULT_KEY, string iv = ConstData.DEFAULT_IV, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }
            if (key.Length > 32)
            {
                key = key.Substring(32);
            }
            key = key.PadRight(32, '0');

            if (iv.Length > 16)
            {
                iv = key.Substring(16);
            }
            iv = iv.PadRight(16, '0');
            byte[] str_arr = Convert.FromBase64String(str);
            byte[] key_arr = encode.GetBytes(key);
            byte[] iv_arr = null;
            if (!string.IsNullOrWhiteSpace(iv))
            {
                iv_arr = encode.GetBytes(iv);
            }
            byte[] resultArray = Decrypt(str_arr, key_arr, iv_arr);
            return encode.GetString(resultArray).Replace("\0", ""); ;
        }
        /// <summary>
        /// AES-CBC-PKCS7 解密
        /// </summary>
        /// <param name="str">16进制字符</param>
        /// <param name="key">密钥，32位以内</param>
        /// <param name="iv">向量,16位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string Decrypt(string str, string key = ConstData.DEFAULT_KEY, string iv = ConstData.DEFAULT_IV, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }

            if (key.Length > 32)
            {
                key = key.Substring(32);
            }
            key = key.PadRight(32, '0');
            if (iv.Length > 16)
            {
                iv = key.Substring(16);
            }
            iv = iv.PadRight(16, '0');

            List<byte> lstBytes = new List<byte>();
            for (int i = 0; i < str.Length; i += 2)
            {
                lstBytes.Add(Convert.ToByte(str.Substring(i, 2), 16));
            }
            byte[] str_arr = lstBytes.ToArray();
            byte[] key_arr = encode.GetBytes(key);
            byte[] iv_arr = null;
            if (!string.IsNullOrWhiteSpace(iv))
            {
                iv_arr = encode.GetBytes(iv);
            }
            byte[] resultArray = Decrypt(str_arr, key_arr, iv_arr);
            return encode.GetString(resultArray).Replace("\0", ""); ;
        }
        #endregion
    }
}
